/*
 * program.h
 *
 *  Created on: Aug 8, 2013
 *      Author: troy
 */

#ifndef PROGRAM_H_
#define PROGRAM_H_

#include <memory.h>
#include <iostream>
#include <cstdlib>
#include <cmath>
#include <algorithm>

using namespace std;

enum operations {
	AND, OR, XOR, NOT, INC, DEC, IF, GOTO, CP, RET, NOPS
};

#define DO_AND(x,y) (x&y)
#define DO_OR(x,y) (x|y)
#define DO_NOT(x) ~x
#define DO_XOR(x,y) (x^y)
#define DO_INC(x) (++x)
#define DO_DEC(x) (--x)

const short IN_LEN = 12;
const short OUT_LEN = 12;
const short WORK_LEN = 32;
const short CODE_LEN = 32;

const char* op_to_str(operations op);

struct memory {
	memory() {
		memset(input, 0, IN_LEN);
		memset(work, 0, WORK_LEN);
		memset(output, 0, OUT_LEN);
	}
	char input[IN_LEN];
	char work[WORK_LEN];
	char output[OUT_LEN];
	void print();
};

struct instruction {
	instruction(bool rnd = false);
	instruction(const instruction& a, bool mutate);
	instruction(operations _op, short _op1 = -1, short _op2 = -1, short _res =
			-1);
	operations op;
	short op1, op2, res; // location in memory of operands
	void Do(char* mem, int& ip);
};

struct result {
	result() :
			mem(0), score(-HUGE_VAL) {
	}
	result(memory* _mem) :
			mem(_mem), score(-HUGE_VAL) {
	}
	result(memory* _mem, double _score) :
			mem(_mem), score(_score) {
	}
	memory* mem;
	double score;
};

struct program {
	program() {
		for (int n = 0; n < CODE_LEN; n++)
			instructions[n].op = NOPS;
		//score = -HUGE_VAL;
	}
	program(const program& a) {
		for (int n = 0; n < CODE_LEN; n++)
			instructions[n] = a.instructions[n];
		score = a.score;
		//score = -HUGE_VAL;
	}
	instruction instructions[CODE_LEN];
	memory mem;
	int counter;
	double score;

	void mutate() {
		int a = rand();
		int b = rand();
		if (a % (CODE_LEN * 3) == 0)
			instructions[a % CODE_LEN] = instruction(true);
		if (b % (3 * CODE_LEN / 2) == 0)
			instructions[b % CODE_LEN] = instruction(instructions[b % CODE_LEN],
					true);
		score = -HUGE_VAL;
	}

// returns a pointer to a OUT_LEN sized output
	result run(const char* in, short len);
	double train(const char* in, short inlen, const char* out, short outlen,
			result* outr = 0);
	static bool comprog(const program& a, const program& b);
};

struct population {
	int size;
	program* progs;
	population(int _size) :
			size(_size), progs(new program[_size]) {
	}
	~population() {
		delete[] progs;
		progs = 0;
		size = 0;
	}
};

#endif /* PROGRAM_H_ */
